package com.sharp.socket.io.config;

import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIONamespace;
import com.corundumstudio.socketio.SocketIOServer;
import com.sharp.authorization.holder.TokenHolder;
import com.sharp.socket.io.dao.redis.LiveCustomerLastLeaveRepository;
import com.sharp.socket.io.exception.SocketNotIntiFinishException;
import com.sharp.socket.io.service.LiveSessionService;
import com.sharp.socket.io.service.SendMessageService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.scheduling.annotation.Async;

import javax.annotation.Resource;
import java.util.UUID;

import static com.sharp.socket.io.constant.ChatMessageConstant.SYS_LIVE_JOIN_ROOM_NOTIFY;

/**
 * Title: SocketIoEndPoint
 * Description: Copyright: Copyright (c) 2019 Company: BHFAE
 *
 * @author Sharp
 * @date 2020/9/22 15:56
 * @description Project Name: customer-robot
 * @Package: com.bhfae.customer.robot.controller
 */
@Slf4j
public class SocketIoEndpoint {

    @Resource
    private LiveSessionService liveSessionService;
    @Resource
    private SocketIOServer socketIOServer;
    @Resource
    private SendMessageService sendMessageService;
    @Autowired
    private BaseLiveSocketIoConfig baseLiveSocketIoConfig;
    @Resource
    private LiveCustomerLastLeaveRepository liveCustomerLastLeaveRepository;

    public boolean onConnect(SocketIOClient client) {
        String operator = client.getHandshakeData().getSingleUrlParam(BaseLiveSocketIoConfig.OPERATOR);
        String token = client.getHandshakeData().getSingleUrlParam(BaseLiveSocketIoConfig.TOKEN);
        String roomId = client.getHandshakeData().getSingleUrlParam(BaseLiveSocketIoConfig.ROOM_ID);
        String namespace = liveSessionService.buildSocketIoNamespace(operator);
        buildSocketIONamespace(namespace);
        boolean login = liveSessionService.hasLogin(operator);
        log.info("[{}]客户 {} 连接", operator, login ? "已登录" : "未登录");
        UUID sessionId = client.getSessionId();
        return liveSessionService.login(operator, roomId, token, sessionId);
    }

    private SocketIONamespace buildSocketIONamespace(String namespace) {
        SocketIONamespace socketIONamespace = socketIOServer.getNamespace(namespace);
        if (socketIONamespace == null) {
            log.info("创建namespace: {}", namespace);
            socketIONamespace = socketIOServer.addNamespace(namespace);
            baseLiveSocketIoConfig.addEventDataListener(socketIOServer, socketIONamespace);
        }
        return socketIONamespace;
    }

    @Async
    public void joinRoomAsync(ApplicationContext applicationContextInstance, String namespace, SocketIOClient client) {
        String roomId = client.getHandshakeData().getSingleUrlParam(BaseLiveSocketIoConfig.ROOM_ID);
        String token = client.getHandshakeData().getSingleUrlParam(BaseLiveSocketIoConfig.TOKEN);
        applicationContextInstance.getBean(this.getClass()).joinRoom(namespace, client.getSessionId(), roomId, token);
    }

    @Retryable(value = {SocketNotIntiFinishException.class}, maxAttempts = 10, backoff = @Backoff(delay = 500L, multiplier = 1))
    public void joinRoom(String namespace, UUID sessionId, String roomId, String token) {
        TokenHolder.set(token);
        SocketIOClient client = socketIOServer.getNamespace(namespace).getClient(sessionId);
        if (client != null) {
            log.info("=======Join_Room {}==========", roomId);
            client.joinRoom(roomId);
            sendMessageService.sendSysMsg(socketIOServer.getNamespace(namespace), SYS_LIVE_JOIN_ROOM_NOTIFY, roomId);
            liveCustomerLastLeaveRepository.delete(roomId);
        } else {
            log.info("=======Wait_Join_Room {}==========", roomId);
            throw new SocketNotIntiFinishException();
        }
    }

    public boolean onDisconnect(SocketIOClient client) {
        String operator = client.getHandshakeData().getSingleUrlParam(BaseLiveSocketIoConfig.OPERATOR);
        String token = client.getHandshakeData().getSingleUrlParam(BaseLiveSocketIoConfig.TOKEN);
        log.info("客户 {} 断开", operator);

        String sessionId = client.getSessionId().toString();
        return liveSessionService.logoff(operator, token, sessionId);
    }
}
